/**************************************************************
*
* M3D_COLR.H
*
* Color mathematics
* Colors are represented in two ways: 
* packed DWORD, and m3dCOLOR
**************************************************************/

//
// Color functions transformation
//
#define   m3dARGBMake(a,r,g,b)       (DWORD)((((a) & 0x000000FFUL) << 24) | (((r) & 0x000000FFUL) << 16) | (((g) & 0x000000FFUL) << 8) | (((b) & 0x000000FFUL))) 
#define  _m3dARGBMake(a,rgb)         (DWORD)((((a) & 0x000000FFUL) << 24) | (rgb)) 
#define   m3dARGBGetA(col)           (DWORD)(((col) & 0xFF000000) >> 24)
#define   m3dARGBGetR(col)           (DWORD)(((col) & 0x00FF0000) >> 16)
#define   m3dARGBGetG(col)           (DWORD)(((col) & 0x0000FF00) >> 8)
#define   m3dARGBGetB(col)           (DWORD)(((col) & 0x000000FF) >> 0)
#define   m3dARGBGetRGB(col)         (DWORD)((col) & 0x00FFFFFF)
#define   m3dARGBSetA(col,a)        _m3dARGBMake(a,m3dARGBGetRGB(col))
#define   m3dARGBGetComp(col,comp)   (DWORD)(((col) & (0x000000FF << ((3 - (comp)) * 8))) >> ((3 - (comp)) * 8))
#define   m3dRGB16GetR(col)          ((col >> 11) & 0x1F)
#define   m3dRGB16GetG(col)          ((col >>  5) & 0x3F)
#define   m3dRGB16GetB(col)          ((col >>  0) & 0x1F)

class m3dCOLOR {
public:
   float r, g, b, a;

   m3dCOLOR (void) : r(0.f), g(0.f), b(0.f), a(0.f) {}
   m3dCOLOR (const m3dCOLOR &c) : r(c.r), g(c.g), b(c.b), a(c.a) {}
   //m3dCOLOR (DWORD color) { Extract(color); }
   m3dCOLOR (float intensity) : r(intensity), g(intensity), b(intensity), a(intensity) {}
   m3dCOLOR (int   _r, int   _g, int   _b, int   _a = 255) : r((float)_r), g((float)_g), b((float)_b), a((float)_a) {}
   m3dCOLOR (float _r, float _g, float _b, float _a = 255) : r(_r), g(_g), b(_b), a(_a) {}

   // functions
   __INLINE void      Set              (float _r, float _g, float _b, float _a = 255);
   __INLINE void      Extract          (DWORD color);
   __INLINE DWORD     Pack             (void) const;
   __INLINE void      Clamp            (void);
   __INLINE void      Clamp_0_1        (void);
   __INLINE void      Pow              (float pow);
   __INLINE void      Gamma            (float gamma = 2.2f);  // does not affect alpha channel (only colors)
   __INLINE void      Degamma          (float gamma = 2.2f);  // does not affect alpha channel (only colors)
   __INLINE void      Scale_0_1        (void);
   __INLINE void      Scale_0_255      (void);
   __INLINE float     MaximumRGB       (void) const;
   __INLINE float     MaximumRGBA      (void) const;
   __INLINE float     Intensity        (void) const;
   __INLINE void      PackHDR          (float maxInt);
   __INLINE void      UnpackHDR        (float maxInt);
   __INLINE void      PackHDRDiv       (float maxInt, float hdrRange, float clamp);
   __INLINE void      PackHDRDiv       (float scale);
   __INLINE void      UnpackHDRDiv     (float scale);
   __INLINE void      ExtractFromRGBE  (DWORD rgbe);
   __INLINE DWORD     PackToRGBE       (void) const;
   __INLINE BOOL      IsZero           (void) const;
   __INLINE BOOL      IsZeroRGB        (void) const;
   __INLINE BOOL      IsZeroA          (void) const;
   __INLINE float     Luminance        (void) const;

   __INLINE m3dCOLOR& operator =       (DWORD color);
   __INLINE m3dCOLOR& operator =       (float intensity);
   __INLINE void      operator*=       (const m3dCOLOR& add);
   __INLINE void      operator+=       (const m3dCOLOR& add);
   __INLINE void      operator-=       (const m3dCOLOR& add);
//   __INLINE           operator DWORD   ();
   __INLINE void      operator*=       (float value);  
   __INLINE void      operator/=       (float value);
//   __INLINE void      operator+=       (float value);
//   __INLINE void      operator-=       (float value);

   static m3dCOLOR Lerp(m3dCOLOR const* c0, m3dCOLOR const* c1, float t) {
      return m3dCOLOR(
         c0->r * (1-t) + c1->r * t, 
         c0->g * (1-t) + c1->g * t, 
         c0->b * (1-t) + c1->b * t, 
         c0->a * (1-t) + c1->a * t);
   }
};

__INLINE m3dCOLOR  operator*  (const m3dCOLOR &c1, const m3dCOLOR &c2)  { m3dCOLOR c(c1); c *= c2; return c; }
//__INLINE m3dCOLOR  operator*  (const m3dCOLOR& c1, const float val) const;
//__INLINE m3dCOLOR  operator*  (const float val,    const m3dCOLOR& c1) const;
__INLINE m3dCOLOR  operator+  (const m3dCOLOR &c1, const m3dCOLOR &c2)  { m3dCOLOR c(c1); c += c2; return c; }
//__INLINE m3dCOLOR  operator+  (const m3dCOLOR& c1, const float val) const;
//__INLINE m3dCOLOR  operator+  (const float val,    const m3dCOLOR& c1) const;
__INLINE m3dCOLOR  operator-  (const m3dCOLOR &c1, const m3dCOLOR &c2)  { m3dCOLOR c(c1); c -= c2; return c; }
//__INLINE m3dCOLOR  operator-  (const m3dCOLOR& c1, const float val) const;
//__INLINE m3dCOLOR  operator-  (const float val,    const m3dCOLOR& c1) const;


/*************************************************************
* m3dCOLOR::Extract()
*
*************************************************************/
__INLINE BOOL m3dIsEqualColor_A (m3dCOLOR const *a, m3dCOLOR const *b, float acc = M3D_EPSILON)
{
   return m3dIsEqual_A(a->r, b->r, acc) && m3dIsEqual_A(a->g, b->g, acc) && 
          m3dIsEqual_A(a->b, b->b, acc) && m3dIsEqual_A(a->a, b->a, acc);
}
// Use this function if you expect the answer to be TRUE most of the time.
__INLINE BOOL m3dIsEqualColor_A_ExpectTrue (m3dCOLOR const *a, m3dCOLOR const *b, float acc = M3D_EPSILON)
{
#if defined _AP_XENON && !defined M3D_SUPPRESS_OPTIMIZATION
	// Most of the time this function returns TRUE, which means each && is going to be
	// evaluated, which means lots of fcmp, which is slow.
	// Here's a nearly branchless version, about 25%-30% faster in the case that the
	// answer is TRUE.
	const XMVECTOR av = __loadunalignedvector(a);
	const XMVECTOR bv = __loadunalignedvector(b);
	const XMVECTOR accv = {acc, acc, acc, acc};

	return XMVector4NearEqual(av, bv, accv);
#elif defined _AP_PS3 && !defined M3D_SUPPRESS_OPTIMIZATION
	const vec_float4 av = vec_load_unaligned((float*)a);
	const vec_float4 bv = vec_load_unaligned((float*)b);
	const vec_float4 accv = {acc, acc, acc, acc};

	const vec_float4 delta = vec_sub(av, bv);

	return vec_all_in(delta, accv);
#else
	return m3dIsEqualColor_A(a, b, acc);
#endif
}
/*************************************************************
* m3dCOLOR::Extract()
*
*************************************************************/
__INLINE void m3dCOLOR::Set (float _r, float _g, float _b, float _a)
{                
   r = _r; b = _b; g = _g; a = _a;
   return;
}

/*************************************************************
* m3dCOLOR::Extract()
*
*************************************************************/
__INLINE void m3dCOLOR::Extract (DWORD color)
{                
   this->r = (float)m3dARGBGetR(color);
   this->g = (float)m3dARGBGetG(color);
   this->b = (float)m3dARGBGetB(color);
   this->a = (float)m3dARGBGetA(color);
   return;
}

/*************************************************************
* m3dCOLOR::Pack()
*
*************************************************************/
__INLINE DWORD m3dCOLOR::Pack (void) const
{
   ASSERT(int(a) >= 0 && int(a) <= 255);
   ASSERT(int(r) >= 0 && int(r) <= 255);
   ASSERT(int(g) >= 0 && int(g) <= 255);
   ASSERT(int(b) >= 0 && int(b) <= 255);

   return m3dARGBMake(((int)a), ((int)r), ((int)g), ((int)b));
}
/*************************************************************
* m3dCOLOR::Clamp()
*
*************************************************************/
__INLINE void m3dCOLOR::Clamp (void) 
{
   a = _m3dClamp(0.f, 255.f, a);
   r = _m3dClamp(0.f, 255.f, r);
   g = _m3dClamp(0.f, 255.f, g);
   b = _m3dClamp(0.f, 255.f, b);
}
/*************************************************************
* m3dCOLOR::Clamp_0_1()
*
*************************************************************/
__INLINE void m3dCOLOR::Clamp_0_1 (void) 
{
   a = _m3dClamp(0.f, 1, a);
   r = _m3dClamp(0.f, 1, r);
   g = _m3dClamp(0.f, 1, g);
   b = _m3dClamp(0.f, 1, b);
}
/*************************************************************
* m3dCOLOR::Pow ()
*
*************************************************************/
__INLINE void m3dCOLOR::Pow (float pow)
{
   ASSERT(a <= 1.f && r <= 1.f && g <= 1.f && b <= 1.f);
   a = m3dPow(a, pow);
   r = m3dPow(r, pow);
   g = m3dPow(g, pow);
   b = m3dPow(b, pow);
}
/*************************************************************
* m3dCOLOR::Gamma ()
*
*************************************************************/
__INLINE void m3dCOLOR::Gamma (float gamma)
{
   ASSERT(r <= 1.f && g <= 1.f && b <= 1.f);
   r = m3dPow(r, gamma);
   g = m3dPow(g, gamma);
   b = m3dPow(b, gamma);
}
/*************************************************************
* m3dCOLOR::Gamma ()
*
*************************************************************/
__INLINE void m3dCOLOR::Degamma (float gamma)
{
   ASSERT(r <= 1.f && g <= 1.f && b <= 1.f);
   float degamma = 1.f / gamma;
   r = m3dPow(r, degamma);
   g = m3dPow(g, degamma);
   b = m3dPow(b, degamma);
}
/*************************************************************
* m3dCOLOR::Scale_0_1 ()
*
*************************************************************/
__INLINE void m3dCOLOR::Scale_0_1 (void)
{
   *this /= 255.f;
}
/*************************************************************
* m3dCOLOR::Scale_0_255 ()
*
*************************************************************/
__INLINE void m3dCOLOR::Scale_0_255 (void)
{
   ASSERT(a <= 1.f && r <= 1.f && g <= 1.f && b <= 1.f);
   *this *= 255.f;
}

/*************************************************************
* m3dCOLOR::MaximumRGB ()
* Returns the greatest of RGB components
*************************************************************/
__INLINE float m3dCOLOR::MaximumRGB (void) const
{
   float rg = r > g ? r : g;
   return rg > b ? rg : b;
}

/*************************************************************
* m3dCOLOR::MaximumRGBA ()
* Returns the greatest of RGB and Alpha components
*************************************************************/
__INLINE float m3dCOLOR::MaximumRGBA (void) const
{
   float rg = r > g ? r : g;
   float ba = b > a ? b : a;
   return rg > ba ? rg : ba;
}

/*************************************************************
* m3dCOLOR::Intensity ()
* Returns RGB average
*************************************************************/
__INLINE float m3dCOLOR::Intensity (void) const
{
   return (r + g + b) / 3.f;
}

/*************************************************************
* m3dCOLOR::Luminance()
*
*************************************************************/
__INLINE float m3dCOLOR::Luminance(void) const
{
   return r * .3f + g * .59f + b * 0.11f;
}
/***************************************************************
* m3dCOLOR::PackHDR ()
***************************************************************/
void m3dCOLOR::PackHDR (float maxInt) 
{
   a = MaximumRGB();
   if(a > 0) {
      *this /= m3dSqrt(a * maxInt);
   }
}

/***************************************************************
* m3dCOLOR::UnpackHDR ()
***************************************************************/
void m3dCOLOR::UnpackHDR (float maxInt) 
{
   *this *= (a * maxInt);
   a = 0.f;
}

/***************************************************************
* m3dCOLOR::PackHDRDiv ()
***************************************************************/
void m3dCOLOR::PackHDRDiv(float maxInt, float hdrRange, float clamp)
{
   // normalize to [0;1/clamp]
   *this /= (maxInt * clamp);

   // clamp
   Clamp_0_1();

   // r,g,b [0;hdrRange]
   PackHDRDiv(1.f / hdrRange);
}

/***************************************************************
* m3dCOLOR::PackHDRDiv ()
***************************************************************/
void m3dCOLOR::PackHDRDiv(float scale)
{
   a = scale;
   *this /= MaximumRGBA();
}

/***************************************************************
* m3dCOLOR::UnpackHDRDiv ()
***************************************************************/
void m3dCOLOR::UnpackHDRDiv(float scale)
{
   *this *= (scale / a);
   a = 1.f;
}

/***************************************************************
* m3dCOLOR::ExtraxtFromRGBE()
***************************************************************/
void m3dCOLOR::ExtractFromRGBE(DWORD rgbe)
{ 
   a = 1.f;
   if (m3dARGBGetA(rgbe) != 0) {
      float factor = ldexp(1.f, m3dARGBGetA(rgbe) - (128 + 8));
      r = m3dARGBGetR(rgbe) * factor;
      g = m3dARGBGetG(rgbe) * factor;
      b = m3dARGBGetB(rgbe) * factor;
   }
   else {
      r = g = b = 0.f;
   }
}

/***************************************************************
* m3dCOLOR::PackToRGBE()
***************************************************************/
DWORD m3dCOLOR::PackToRGBE(void) const
{
   float sup = MaximumRGB();

   if (sup < 1e-7)
      return 0;

   int eint;
   float factor = frexp(sup, &eint) * 256.f / sup;
   return m3dARGBMake( eint + 128, (int)(r * factor), (int)(g * factor), (int)(b * factor) );
}


/*************************************************************
* m3dCOLOR::IsZero()
*
*************************************************************/
__INLINE BOOL m3dCOLOR::IsZero (void) const
{
   if (m3dIsZero_A(a, 1.f/255.f) && m3dIsZero_A(r, 1.f/255.f) && 
       m3dIsZero_A(g, 1.f/255.f) && m3dIsZero_A(b, 1.f/255.f)) {
      return TRUE;
   }
   return FALSE;
}

/*************************************************************
* m3dCOLOR::IsZeroRGB()
*
*************************************************************/
__INLINE BOOL m3dCOLOR::IsZeroRGB (void) const
{
   if (m3dIsZero_A(r, 1.f/255.f) && 
       m3dIsZero_A(g, 1.f/255.f) && m3dIsZero_A(b, 1.f/255.f)) {
      return TRUE;
   }
   return FALSE;
}

/*************************************************************
* m3dCOLOR::IsZeroA()
*
*************************************************************/
__INLINE BOOL m3dCOLOR::IsZeroA (void) const
{
   if (m3dIsZero_A(a, 1.f/255.f)) {
      return TRUE;
   }
   return FALSE;
}

/*************************************************************
* m3dCOLOR::operator= ()
*
*************************************************************/
__INLINE m3dCOLOR& m3dCOLOR::operator = (float intensity)
{
   this->r = intensity;
   this->g = intensity;
   this->b = intensity;
   this->a = intensity;
   return *this;
}
/*************************************************************
* m3dCOLOR::operator= ()
*
*************************************************************/
__INLINE m3dCOLOR& m3dCOLOR::operator = (DWORD color)
{
   Extract(color);
   return *this;
}
/*************************************************************
* m3dCOLOR::operator*= ()
*
*************************************************************/
__INLINE void m3dCOLOR::operator*= (const m3dCOLOR& add)
{
   this->r *= add.r;
   this->g *= add.g;
   this->b *= add.b;
   this->a *= add.a;
   return;
}
/*************************************************************
* m3dCOLOR::operator+= ()
*
*************************************************************/
__INLINE void m3dCOLOR::operator+= (const m3dCOLOR& add)
{
   this->r += add.r;
   this->g += add.g;
   this->b += add.b;
   this->a += add.a;
   return;
}
/*************************************************************
* m3dCOLOR::operator-= ()
*
*************************************************************/
__INLINE void m3dCOLOR::operator-= (const m3dCOLOR& add)
{
   this->r -= add.r;
   this->g -= add.g;
   this->b -= add.b;
   this->a -= add.a;
   return;
}
/*************************************************************
* m3dCOLOR::operator*= ()
*
*************************************************************/
__INLINE void m3dCOLOR::operator*= (float value)
{
   this->r *= value;
   this->g *= value;
   this->b *= value;
   this->a *= value;
   return;
}
/*************************************************************
* m3dCOLOR::operator/= ()
*
*************************************************************/
__INLINE void m3dCOLOR::operator/= (float value)
{
   this->r /= value;
   this->g /= value;
   this->b /= value;
   this->a /= value;
   return;
}


/*************************************************************
* m3dCOLOR::operator* ()
*************************************************************
__INLINE m3dCOLOR m3dCOLOR::operator* (const float val) const
{
   m3dCOLOR c;

   c.a = a * val;
   c.r = r * val;
   c.g = g * val;
   c.b = b * val;
   return c;
}*/

/*************************************************************
* m3dCOLOR::operator DWORD()
*
*************************************************************
__INLINE m3dCOLOR::operator DWORD ()
{
   return Pack();
}*/


//
// Bit Mask functions
//
/************************************************************
* m3dMaskGetShiftLength ()
*    Extract shift and length of color component bit mask
* IN:  mask - bit mask 
* OUT: shift  - bit mask shift 
*      length - bit mask length
* RET: FALSE of this is incorrect mask
************************************************************/
__INLINE BOOL  m3dMaskGetShiftLength (DWORD mask, int *shift, int *length = NULL)
{
   int   first, last;
   // Scan mask and extract first and last bits

   if (mask == 0x00000000) {
      goto exit_with_error;
   }

   for (first = 0; first < 32; first++) {
      if (mask & (1 << first)) {
         break;
      }
   }
   if (first == 32) {
      // no first bit found -> incorrect mask
      goto exit_with_error;
   }
   for (last = first; last < 32; last++) {
      if (!(mask & (1 << last))) {
         last--;
         break;
      }
   }
   if (last == 32) {
      last = 31;
   }
   if ((last < 31) && (mask != ((DWORD)((1 << (last-first+1)) - 1) << first))) {
      // incorrect mask
      goto exit_with_error;
   } 
   if (shift) {
      *shift  = first;
   }
   if (length) {
      *length = 1 + last - first;
   }

//   bitInfo = (WORD)((last << 8) | first);
//   *shift  = (BYTE)(bitInfo & 0x00FF);
//   *length = 1 + (BYTE)(bitInfo>>8) - (BYTE)bitInfo;
   
   return TRUE;
exit_with_error:
   if (shift) {
      *shift  = 0;
   }
   if (length) {
      *length = 0;
   }
   return FALSE;
}

__INLINE BOOL  m3dMaskGetShiftLength64(UINT64 mask, int *shift, int *length = NULL)
{
   int   first, last;
   // Scan mask and extract first and last bits

   if (mask == UINT64(0)) {
      goto exit_with_error;
   }

   for (first = 0; first < 64; first++) {
      if (mask & (UINT64(1) << UINT64(first))) {
         break;
      }
   }
   if (first == 64) {
      // no first bit found -> incorrect mask
      goto exit_with_error;
   }
   for (last = first; last < 64; last++) {
      if (!(mask & (UINT64(1) << UINT64(last)))) {
         last--;
         break;
      }
   }
   if (last == 64) {
      last = 63;
   }
   if ((last < 63) && (mask != ((UINT64)((UINT64(1) << UINT64(last-first+1)) - UINT64(1)) << first))) {
      // incorrect mask
      goto exit_with_error;
   } 
   if (shift) {
      *shift  = first;
   }
   if (length) {
      *length = 1 + last - first;
   }

   //   bitInfo = (WORD)((last << 8) | first);
   //   *shift  = (BYTE)(bitInfo & 0x00FF);
   //   *length = 1 + (BYTE)(bitInfo>>8) - (BYTE)bitInfo;

   return TRUE;
exit_with_error:
   if (shift) {
      *shift  = 0;
   }
   if (length) {
      *length = 0;
   }
   return FALSE;
}


/************************************************************************
* m3dMaskExtractColor ()
*    Extract color component from color
* IN:  color  - pixel color
*      mask   - bit mask
*      shift  - bit mask shift 
*      length - bit mask length
* OUT: none
* RET: color value of the given channel in [0..1]
************************************************************************/
__INLINE float m3dMaskExtractColor (DWORD color, DWORD mask, int shift, int length)
{
   color  &= mask;
   color >>= shift;
   return ((float)color)/((1 << length) - 1);
}
/************************************************************************
* m3dMaskExtractColor ()
*    Extract color component from color
* IN:  dword - pixel color
*      mask  - mask for a fixed color channel
* OUT: none
* RET: color value of the given channel in [0..1]
************************************************************************/
__INLINE float m3dMaskExtractColor (DWORD color, DWORD mask)
{
   int    shift, length;

   m3dMaskGetShiftLength(mask, &shift, &length);
   return m3dMaskExtractColor(color, mask, shift, length);
}


/************************************************************************
* m3dMaskPackColor ()
*    Pack color component to color
* IN:  color  - pixel color
*      shift  - bit mask shift 
*      length - bit mask length
* OUT: none
* RET: color value of the given channel 
************************************************************************/
__INLINE DWORD m3dMaskPackColor (float color, int shift, int length)
{
   DWORD  res;

   res = (DWORD)(color * ((1 << length) - 1));
   return res << shift;
}
/************************************************************************
* m3dMaskPackColor ()
*    Pack color component to color
* IN:  dword - pixel color in [0..1]
*      mask  - mask for a fixed channel
* OUT: none
* RET: color value of the given channel 
************************************************************************/
__INLINE DWORD m3dMaskPackColor (float color, DWORD mask)
{
   int    shift, length;

   m3dMaskGetShiftLength(mask, &shift, &length);
   return m3dMaskPackColor(color, shift, length);
}
/***********************************************************************
* m3dMaskConvertColor ()
*    Fast conversion from one color format to another
* IN : srcColor - source color
*      srcMask, srcShift - source color format 
*      dstShift, ratio - destination color format 
* OUT: none
* RET: converted color
***********************************************************************/
__INLINE DWORD m3dMaskConvertColor(DWORD srcColor, DWORD srcMask, int srcShift, int dstShift, float ratio)
{
   srcColor  = (srcColor & srcMask) >> srcShift;

   if (ratio != 1.f) {
      srcColor = (DWORD)(((float)srcColor) * ratio);
   }
   return srcColor << dstShift;
}
/***********************************************************************
* m3dMaskDWord2Buffer ()
* IN : bpp   - pits per pixel (1,2,3,4)
*      dword - DWORD color in appropriate bitmask format
* OUT: write 'dword' to the 'bpp' bytes in the buffer
* RET: none
***********************************************************************/
__INLINE void m3dMaskDWord2Buffer (int bpp, BYTE *buffer, DWORD dword)
{
   switch (bpp) {
      case 1:
         *buffer = (BYTE)dword;
         break;
      case 2:
         *((WORD*)buffer) = (WORD)dword;
         break;
      case 3:
         buffer[0] = (BYTE)dword;
         buffer[1] = (BYTE)(dword>>8);
         buffer[2] = (BYTE)(dword>>16);
         break;
      case 4:
         *((DWORD*)buffer) = dword;
         break;
      default:
         ASSERT(FALSE);
         break;
   }
   return;
}
/***********************************************************************
* m3dMaskDWord2Buffer ()
* IN : bpp    - pits per pixel (1,2,3,4)
*      buffer - buffer with image
*      dword - DWORD color in appropriate bitmask format
* OUT: none
* RET: DWORD color in appropriate bitmask format
***********************************************************************/
__INLINE DWORD m3dMaskBuffer2DWord (int bpp, BYTE *buffer)
{
   DWORD color;

   switch (bpp) {
      case 1:
         color = *buffer;
         break;
      case 2:
         color = (buffer[1] << 8) | buffer[0];
         break;
      case 3:
         color = (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
         break;
      case 4:
         color = (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
         break;
      default:
         color = 0xFFFFFFFF;
         ASSERT(FALSE);
         break;
   }
   return color;
}

/***********************************************************************
* m3dMaskDWord2BufferReverce ()
* IN : bpp   - pits per pixel (1,2,3,4)
*      dword - DWORD color in appropriate bitmask format
* OUT: write 'dword' to the 'bpp' bytes in the buffer
* RET: none
***********************************************************************/
__INLINE void m3dMaskDWord2BufferReverce (int bpp, BYTE *buffer, DWORD dword)
{
   BYTE  byte[4];
   int   i;

   byte[0] = (BYTE)(((dword) & 0xFF000000) >> 24);
   byte[1] = (BYTE)(((dword) & 0x00FF0000) >> 16);
   byte[2] = (BYTE)(((dword) & 0x0000FF00) >>  8);
   byte[3] = (BYTE)(((dword) & 0x000000FF) >>  0);

   for (i = 4-bpp; i < 4; i++) {
      *buffer++ = byte[i];
   }

   return;
}
/***********************************************************************
* m3dMaskBuffer2DWordReverce ()
* IN : bpp    - pits per pixel (1,2,3,4)
*      buffer - buffer with image
*      dword - DWORD color in appropriate bitmask format
* OUT: none
* RET: DWORD color in appropriate bitmask format
***********************************************************************/
__INLINE DWORD m3dMaskBuffer2DWordReverce (int bpp, BYTE *buffer)
{
   DWORD color = 0;

   switch (bpp) {
      case 1:
         color = *buffer;
         break;
      case 2:
         color = (buffer[0] << 8) | buffer[1];
         break;
      case 3:
         color = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
         break;
      case 4:
         color = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
         break;
      default:
         ASSERT(FALSE);
         break;
   }
   return color;
}
//
// End-of-file M3D_COLR.H
//
